Technical Q&A TX09
Translating Postscript font file names

Q How I can translate a font name to a Postscript font file name?

A The name of the Postscript font can be determined using information stored inside the FOND resource. This information is stored in the Style-Mapping table, which is described on pages 4-99 through 4-105 in Inside Macintosh: Text. Essentially, you'll take the FOND and style information, and build the complete Postscript name.

If you need the name of the Postscript font file, you can condense the Postscript name into the name of the file. The rule is to take the first 5 characters in the font name, and then add the first 3 characters that follow any dash. For example, the following Helvetica font:

Helvetica-Bold-Oblique-Condensed

Would become:

HelveBolOblCon

Once you've got the font file name, you can search for the corresponding file. The file type is 'LWFN' and creator is 'ASPF'. Note that the font can be stored in multiple suitcases.

  • Fonts folder
  • Extensions folder (because in 7.0 there was no fonts folder)
  • System Folder (because in 6.x this is where Postscript files were stored)
  • The same folder as the file that holds the FOND resource (because Suitcase allows you to store Postscript fonts outside the System Folder).

One last thing -- the font can be stored in multiple suitcases, so if you get to the last step above, you'll need to search all available FOND resources for that font.

Below are a couple of snippets of code -- one is a C translation of the Style Mapping code found in Inside Macintosh: Text, and the other is code I've used to walk the list of FOND resources. Finally, MoreFiles is a piece of sample code that may prove useful if you need to search the directories for a particular file.


#include <fonts.h>
#include <Strings.h>

typedef short int16;
typedef long int32;
typedef FamRec **FamRecHdl;
typedef StyleTable *StyleTablePtr;

#define MIN(a,b) ((a)<(b)?(a):(b))


void main (void);
void GetPrinterFontName (Str255 screenName, Str255 printerName);
int32 MyCompressStyle(Style aStyle);
void MyNthStyleName(int32 index, Ptr q, Str255 s);
void MyPSFontName(FamRec **fh, Style aStyle, Str255 PSName);

void ConcatPStrings (Str255 targetStr, ConstStr255Param appendStr);

void ConcatPStrings (Str255 targetStr, ConstStr255Param appendStr)
{
    short appendLen;

    /* Figure out number of bytes to copy, up to 255 */

    appendLen = MIN(appendStr[0], 255 - targetStr[0]);
    if (appendLen > 0) {
        BlockMoveData(appendStr+1, targetStr+targetStr[0]+1, (long) appendLen);
        targetStr[0] += appendLen;
    }
}


void main (void)
{
        Str255 printer;

// do standard mac init
    InitGraf(&qd.thePort);
    InitFonts();
    InitWindows();
    InitMenus();
    TEInit();
    InitDialogs(nil);
    InitCursor();

    MaxApplZone();
    MoreMasters();
    MoreMasters();
    MoreMasters();


    GetPrinterFontName ("\pTimes", printer);
    Debugger();
}

void GetPrinterFontName(Str255 screenName, Str255 printerName)
{
    int16           fontNum;
    FMetricRec  theMetrics;
    WidthTable  **wTabHan;

    GetFNum( screenName, &fontNum);
    TextFont( fontNum );
    TextFace (bold + italic);
    FontMetrics( &theMetrics );
    wTabHan = (WidthTable **) theMetrics.wTabHandle;
    MyPSFontName((FamRecHdl) (**wTabHan).fHand, bold+italic, printerName);
    return;
}

int32 MyCompressStyle(Style aStyle)
    // A "Set of StyleItem" is mapped into [0..47],
    // assuming that condense and extend are mutually exclusive
{
    int32 styleCode;

    styleCode = 0;
    if (bold & aStyle)
        styleCode = styleCode + 1;
    if (italic & aStyle)
        styleCode = styleCode + 2;
    if (outline & aStyle)
        styleCode = styleCode + 4;
    if (shadow & aStyle)
        styleCode = styleCode + 8;

    if (condense & aStyle)
        styleCode = styleCode + 16;
    else if (extend & aStyle)
        styleCode = styleCode + 32;

    return( styleCode );
}

void MyNthStyleName(int32 index, Ptr q, Str255 s)
{
    while (index > 1) {
        q = (Ptr) (q + *q + 1);
        // assumes q^ = stringlength < 128 ...
        index -= 1;
    }
    BlockMove(q, &s[0], *q + 1);
    // assumes q^ = stringlength < 127 ...
    return;
}

void MyPSFontName(FamRec **fh, Style aStyle, Str255 PSName)
{
    StyleTablePtr stp;
    Ptr     q;              // pointer to Style-name table.
    Str255  styleName, suffixIndices;
    int32   i, nbOfStrings, offset, whichIndex;

    PSName[0] = '0';
    offset = (**fh).ffStylOff;
    if (offset > 0) {
        q = ((Ptr) *fh) + offset;
        stp = (StyleTablePtr) q;
        q += sizeof (StyleTable);

            // style-name table follows style-mappingTable
        nbOfStrings = *(SInt16 *) q;
            // for range checking below
        q += sizeof (SInt16);
            // now pointing to basename of font
        BlockMove(q, (Ptr) PSName, *q + 1);
            // basename of font; assumes length < 128
        whichIndex = stp->indexes[MyCompressStyle(aStyle)];
        if (whichIndex > 1  &&  whichIndex <= nbOfStrings) {
            MyNthStyleName(whichIndex, q, suffixIndices);
            for (i=1;i <= suffixIndices[0];++i) {
                MyNthStyleName(suffixIndices[i], q, styleName);
                ConcatPStrings( PSName, styleName);
            }
        }
    }
        //ELSE  corrupted FOND
    //else // no style mapping table in FOND
        //return( PSName );
}


#define _SanityCheck_ 1

#ifndef _SanityCheck_
    #define _SanityCheck_ 1
#endif

// Note that these don't set any error variables -- in general, any routines that report
// an OSErr should have a variable inside the routine that gets set appropriately -- and
// reports a "default" error code when it isn't already set to noErr.

#if _SanityCheck_
    #define FAIL_NIL(y,msg)         {if (y == NULL) {DebugStr(msg); goto error;}}
    #define FAIL_OSERR(y,msg)       {if (y != noErr) {DebugStr(msg); goto error;}}
    #define FAIL_FALSE(y,msg)       {if (!y) {DebugStr(msg); goto error;}}
    #define SIGNAL_ERROR(msg)       {DebugStr(msg); goto error;}
#else
    #define FAIL_NIL(y,msg)         {if (y == NULL) {goto error;}}
    #define FAIL_OSERR(y,msg)       {if (y != noErr) { goto error;}}
    #define FAIL_FALSE(y,msg)       {if (!y) {goto error;}}
    #define SIGNAL_ERROR(msg)       {goto error;}
#endif


void main (void);


// This routine returns the first available installed file that
// includes the font passed in.
// It also returns a magic cookie that can be used to
// retrieve any other files that
// contain that font.

OSErr   FontNameToFSSpec (ConstStr31Param inFont, FSSpec *outFile, long *outCookie);
OSErr   NextFontToFSSpec (long *inOutCookie, FSSpec *outFile);


// We borrow these routines from MoreFiles, since they are so handy.
/*****************************************************************************/

pascal  OSErr   GetFileLocation(short refNum,
                                short *vRefNum,
                                long *dirID,
                                StringPtr fileName);
/*  Get the location of an open file.
    The GetFileLocation function gets the location (volume reference number,
    directory ID, and fileName) of an open file.

    refNum      input:  The file reference number of an open file.
    vRefNum     output: The volume reference number.
    dirID       output: The parent directory ID.
    fileName    input:  Points to a buffer (minimum Str63) where the
                        filename is to be returned or must be nil.
                output: The filename.

    Result Codes
        noErr               0       No error
        nsvErr              -35     Specified volume doesn't exist
        fnOpnErr            -38     File not open
        rfNumErr            -51     Reference number specifies nonexistent
                                    access path

    __________

    See also:   FSpGetFileLocation
*/

/*****************************************************************************/

pascal  OSErr   FSpGetFileLocation(short refNum,
                                   FSSpec *spec);
/*  Get the location of an open file in an FSSpec record.
    The FSpGetFileLocation function gets the location of an open file in
    an FSSpec record.

    refNum      input:  The file reference number of an open file.
    spec        output: FSSpec record containing the file name and location.

    Result Codes
        noErr               0       No error
        nsvErr              -35     Specified volume doesn't exist
        fnOpnErr            -38     File not open
        rfNumErr            -51     Reference number specifies nonexistent
                                    access path

    __________

    See also:   GetFileLocation
*/



/*****************************************************************************/

pascal  OSErr   GetFileLocation(short refNum,
                                short *vRefNum,
                                long *dirID,
                                StringPtr fileName)
{
    FCBPBRec pb;
    OSErr error;

    pb.ioNamePtr = fileName;
    pb.ioVRefNum = 0;
    pb.ioRefNum = refNum;
    pb.ioFCBIndx = 0;
    error = PBGetFCBInfoSync(&pb);
    *vRefNum = pb.ioFCBVRefNum;
    *dirID = pb.ioFCBParID;
    return ( error );
}

/*****************************************************************************/

pascal  OSErr   FSpGetFileLocation(short refNum,
                                   FSSpec *spec)
{
    return ( GetFileLocation(refNum, &(spec->vRefNum), &(spec->parID), spec->name) );
}




OSErr   FontNameToFSSpec (ConstStr31Param inFont, FSSpec *outFile, long *outCookie)
{
    OSErr theErr= noErr;
    short homeFile;

    Handle fond;
    *outCookie = NULL;

    fond = GetNamedResource('FOND', inFont);
    theErr = ResError();
    FAIL_OSERR (theErr, "\p Failed to find any installed font file with that font name")
    FAIL_NIL (fond, "\p Failed to find any installed font file with that font name")

    homeFile = HomeResFile (fond);
    theErr = ResError();
    FAIL_OSERR (theErr, "\p Failed to find the resource's home")

    theErr = FSpGetFileLocation(homeFile, outFile);
    FAIL_OSERR (theErr, "\p couldn't convert the reference to a file spec")

    // We succeeded.  Set our cookie and return.
    *outCookie = (long) fond;

    return noErr;

    error:
    if (theErr != noErr)
        theErr = paramErr;
    *outCookie = NULL;
    return theErr;
}


OSErr   NextFontToFSSpec (long *inOutCookie, FSSpec *outFile)
{
    OSErr theErr= noErr;
    short homeFile;

    Handle fond = (Handle) *inOutCookie;

    if (fond == NULL) return paramErr;

    fond = GetNextFOND (fond);
    theErr = ResError();
    FAIL_OSERR (theErr, "\p No more fonds left with that name")
    FAIL_NIL (fond, "\p No more fonds left with that name")

    homeFile = HomeResFile (fond);
    theErr = ResError();
    FAIL_OSERR (theErr, "\p Failed to find the resource's home")

    theErr = FSpGetFileLocation(homeFile, outFile);
    FAIL_OSERR (theErr, "\p couldn't convert the reference to a file spec")

    // We succeeded.  Set our cookie and return.
    *inOutCookie = (long) fond;

    return noErr;

    error:
    if (theErr != noErr)
        theErr = paramErr;
    *inOutCookie = NULL;
    return theErr;
}

void main (void)
{
    long oreo;
    FSSpec  fontFile;
    OSErr   theErr;

    // We just drop into the debugger here to report the returned FSSpecs.

    theErr = FontNameToFSSpec("\pPalatino", &fontFile, &oreo);
    Debugger();
    while (oreo != 0)
    {
        theErr = NextFontToFSSpec (&oreo, &fontFile);
        Debugger();
    }

}

[Nov 17 1997]


Developer Documentation | Technical Notes | Development Kits | Sample Code